# AI Edit Log — 장애물 회피 로직 개선

작성일: 2026-06-04
대상 브랜치: `feat/no-right-sensor`

## 1. 작업 목표

다음 요구사항에 맞춰 RVC의 장애물 회피 로직과 단위/시스템 테스트를 수정한다.

1. **전방에 장애물이 있는 경우**
   - 1.1 좌측을 확인 후 없으면 좌회전 후 진행
   - 1.2 우측을 확인 후 없으면 우회전 후 진행
   - 1.3 좌/우측이 모두 막혀있으면 후진
2. **후진의 경우**
   - 2.1 3면이 모두 막혀있다면 후진
   - 2.2 한 번 후진 후에는 바로 탈출이 아닌 좌/우측을 탐지 후 비어있는 방향으로 탈출(비어있는 방향으로 회전 후 전진)
   - 2.3 좌/우측이 모두 막혀있는 경우에는 후진을 반복
   - 2.4 10번 후진 후에도 좌/우측에 장애물이 있다면 최종 탈출 불가로 판정해 RVC의 전원 OFF

## 2. 기존 구조 파악 요약

- `feat/no-right-sensor` 브랜치는 **우측 HW 센서를 제거**한 상태이다. 우측 방향 장애물은 `MovementUnit::turn(RIGHT)` 명령 후 **전방 센서(`frontSensor_`)를 재조회**하여 간접 감지한다(시뮬레이터의 `SimFrontSensor`가 이 동작을 모델링).
- `Controller`는 `frontSensor_`, `leftSensor_`, `dustSensor_` 3개 센서만 보유한다.
- 작업 시작 시점의 작업 트리에는 1.1 ~ 2.3 로직의 골격(`tryEscapeToFreeSide()`, 후진 재시도 카운터)이 이미 들어와 있었으나, **2.4(전원 OFF)가 미구현**이었고 일부 테스트가 구(舊) 로직 기준으로 남아 실패하는 상태였다.

## 3. 요구사항 ↔ 구현 매핑

| 요구사항 | 구현 위치 | 동작 |
|---|---|---|
| 1.1 좌측 여유 → 좌회전 후 진행 | `Controller::tryEscapeToFreeSide()` | 좌측 센서 조회 → 비었으면 `turn(LEFT)` + `moveForward()` |
| 1.2 우측 여유 → 우회전 후 진행 | `Controller::tryEscapeToFreeSide()` | 좌측 막힘 시 `turn(RIGHT)` 후 전방 센서 재조회 → 비었으면 `moveForward()` |
| 1.3 좌/우 모두 막힘 → 후진 | `Controller::avoidFrontObstacle()` | `tryEscapeToFreeSide()` 실패 시 `avoidAllDirectionObstacle()` 진입 |
| 2.1 3면 막힘 → 후진 | `Controller::avoidAllDirectionObstacle()` | `stop()` → `moveBackward()` |
| 2.2 후진 후 좌/우 재탐지 후 탈출 | `avoidAllDirectionObstacle()` → `tryEscapeToFreeSide()` | 후진 직후 좌/우를 다시 탐지하여 빈 방향으로 회전+전진 |
| 2.3 좌/우 모두 막힘 → 후진 반복 | `avoidAllDirectionObstacle()` | 탈출 실패 시 `STOPPED`로 복귀, 다음 폴링 틱에서 후진 재시도. `backwardAttempts_` 증가 |
| 2.4 10회 후진 후 탈출 불가 → 전원 OFF | `avoidAllDirectionObstacle()` → `powerOff()` | `backwardAttempts_ >= kMaxBackwardAttempts(10)`이면 `powerOff()` 호출 |

## 4. 변경 내역 (파일별)

### 4.1 `src/rvc/Types.hpp`
- `RVCState` 열거형에 **`POWER_OFF`** 상태 추가. (10회 후진 후 최종 탈출 불가 시 진입하는 종료 상태)

### 4.2 `src/rvc/CleaningUnit.hpp`
- 전원 OFF 시 청소를 정지하기 위한 인터페이스 메서드 **`stopCleaning()`** 추가.

### 4.3 `src/rvc/Controller.hpp`
- 종료 상태 표현을 `stuck_` → **`poweredOff_`**, 조회 메서드를 `isStuck()` → **`isPoweredOff()`** 로 변경(요구사항 2.4의 "전원 OFF" 의미를 명확화).
- 최종 탈출 불가 처리용 private 헬퍼 **`void powerOff();`** 선언 추가.

### 4.4 `src/rvc/Controller.cpp`
- `startCleaning()`: 재가동 시 `poweredOff_ = false`로 초기화.
- `pollSensors()`: `poweredOff_`이면 즉시 반환하여 모든 동작 중단.
- `avoidAllDirectionObstacle()`: 양측 모두 막힘 + `backwardAttempts_ >= kMaxBackwardAttempts`이면 `powerOff()` 호출 후 반환. 그 외에는 `STOPPED`로 복귀하여 다음 틱에 후진 반복(요구사항 2.3).
- **`powerOff()` 신규 구현**: `movementUnit_->stop()` + `cleaningUnit_->stopCleaning()` 호출, `state_ = RVCState::POWER_OFF`, `poweredOff_ = true` 설정.

### 4.5 `src/simulator/SimCleaningUnit.hpp`
- `stopCleaning()` 구현: `active_ = false` (청소 비활성화).

### 4.6 `src/simulator/RVCSimulator.hpp`
- 상태 조회 메서드 `isStuck()` → **`isPoweredOff()`** 로 변경(내부적으로 `controller_.isPoweredOff()` 호출).

### 4.7 `tests/unit/mocks/MockSensors.hpp`
- `MockCleaningUnit`에 `stopCleaning()` MOCK_METHOD 추가.

### 4.8 `tests/unit/ControllerTest.cpp` (단위 테스트)
- `isStuck()` 호출을 모두 `isPoweredOff()` 로 갱신.
- `UC05_TC003_OneBackward_ThenLeftFree_EscapesLeft`: 전방 장애물 단계에서 우측 확인을 위한 `turn(RIGHT)` 호출을 허용하도록 `turn(_)` 캐치올 기대 추가(최종 탈출은 `turn(LEFT)`로 검증). `testing::AnyNumber` using 추가.
- `UC05_TC005_MaxAttemptsExhausted_PowersOff`: 10회 후진 소진 후 `isPoweredOff() == true` 검증으로 갱신(요구사항 2.4).
- `UC05_TC006_PowerOff_StopsCleaningUnit`: 전원 OFF 시 `CleaningUnit::stopCleaning()` 1회 호출 검증 **신규 추가**.
- `UC05_TC007_WhenPoweredOff_PollSensorsDoesNothing`: 전원 OFF 후 폴링이 아무 동작도 하지 않음을 검증(기존 stuck 테스트를 전원 OFF 의미로 갱신).

### 4.9 `tests/system/RVCSimulatorTest.cpp` (시스템 테스트)
- `Scenario3_CornerTrapAndEscape`: 구 로직(후진 1회 후 즉시 전진 탈출) 기대를 **신 로직**으로 수정 — 3면 막힘 시 즉시 전진하지 않고 후진(요구사항 2.3), 이후 좌측이 열리면 좌회전 후 전진 탈출.
- `Scenario7_FullRoomCleaningSession`의 Phase 6: 동일하게 "후진 → 우측 개방 시 우회전 탈출" 흐름으로 수정.
- **`Scenario8_FullyTrapped_PowersOffAfterMaxReversals` 신규 추가**: 전방·좌·우가 지속적으로 막힌 상태에서 9회까지는 전원 OFF가 아니고, 10회 후진 후 `isPoweredOff() == true`, 이동 `STOPPED`, 청소 `getIsActive() == false`, 이후 추가 틱에서 무동작임을 검증(요구사항 2.4).

## 5. 검증 결과

빌드: `cmake --build`(MinGW g++ 15.2, C++17) 성공.
테스트: `ctest` 기준 **56/56 전체 통과**.

- `unit_tests` — Controller / Sensor 단위 테스트
- `integration_tests` — UseCase 기반 통합 테스트(기존 흐름이 신 로직과 정합, 수정 불필요)
- `system_tests` — 시나리오 기반 시스템 테스트(Scenario 1~8)

## 6. 비고

- 우측 HW 센서가 없는 현 설계상 "우측 확인"은 `turn(RIGHT)` 후 전방 센서 재조회로 수행된다. 따라서 좌측이 막힌 회피 과정에서는 `turn(RIGHT)`가 탐지 목적의 부수 동작으로 호출될 수 있다.
- 전원 OFF는 종료(terminal) 상태이며, 재가동은 `startCleaning()` 호출로만 가능하다(이때 `poweredOff_`/`backwardAttempts_` 초기화).
